#include "pieces.h"
#include "board.h"
#include "menu.h"
#include "music.h"
#include "animation.h"

PIECES pieces;
PSELECT pselect_;
SHADOW shadow;

extern unsigned char key[ALLEGRO_KEY_MAX];
extern int crt_board[BOARD_ROW][BOARD_COL];
extern int crt_turn;
extern EAT_BUBBLE eat_bubble;
extern CHECKMATE_BUBBLE checkmate_bubble;
extern WIN_TEXTS win_texts;

extern Game *game;
extern Menu *menu;



ALLEGRO_BITMAP* pieces_grab(int x, int y, int w, int h)
{
    ALLEGRO_BITMAP* sprite;
    sprite = al_create_sub_bitmap(pieces._sheet, x, y, w, h);    
    if(!sprite){
        printf("Error creating sub bitmap\n");
        exit(1);
    }
    return sprite;
}

void pieces_init(){
    gene_board(crt_board);
    pieces._sheet = al_load_bitmap("res/pieces.png");
    if(!pieces._sheet){
        printf("Error loading pieces.png\n");
        exit(1);
    }
    for(int i = 0; i < 14; i++){
        pieces.pieces[i] = pieces_grab(i*100, 0, 100, 100);
    }
}

void pieces_clean(){
    al_destroy_bitmap(pieces._sheet);
    for(int i = 0; i < 14; i++){
        al_destroy_bitmap(pieces.pieces[i]);
    }
}

int get_pieces(int board){
    switch(board){
        case B_GENERAL:
            return 0;
        case R_GENERAL:
            return 1;
        case B_GUARD:
            return 2;
        case R_GUARD:
            return 3;
        case B_MINISTER:
            return 4;
        case R_MINISTER:
            return 5;
        case B_KNIGHT:
            return 6;
        case R_KNIGHT:
            return 7;
        case B_ROOKS:
            return 8;
        case R_ROOKS:
            return 9;
        case B_CANNON:
            return 10;
        case R_CANNON:
            return 11;
        case B_PAWN:
            return 12;
        case R_PAWN:
            return 13;
        default:
            break;
    }
}

void pieces_draw(){
    for(int i = 0; i < BOARD_ROW; i++){
        for(int j = 0; j < BOARD_COL; j++){
            if(crt_board[i][j] != 0){
                al_draw_bitmap(pieces.pieces[get_pieces(crt_board[i][j])],
                BOARD_X + j*95, BOARD_Y + i*95, 0);
            }
        }
    }
}

ALLEGRO_BITMAP* pselect_grab(int x, int y, int w, int h){
    ALLEGRO_BITMAP* sprite;
    sprite = al_create_sub_bitmap(pselect_._sheet, x, y, w, h);    
    if(!sprite){
        printf("Error creating sub bitmap\n");
        exit(1);
    }
    return sprite;
}
void pselect_init(){
    pselect_.selected = false;
    pselect_.x = -1;
    pselect_._sheet = al_load_bitmap("res/piece_select.png");
    if(!pselect_._sheet){
        printf("Error loading piece_select.png\n");
        exit(1);
    }
    for(int i = 0; i < 2; i++){
        pselect_.piece_select[i] = pselect_grab(i*100, 0, 100, 100);
    }
}
void pselect_clean(){
    al_destroy_bitmap(pselect_._sheet);
    for(int i = 0; i < 2; i++){
        al_destroy_bitmap(pselect_.piece_select[i]);
    }
}

void pselect_update(ALLEGRO_EVENT *event){
    if(event->type == ALLEGRO_EVENT_MOUSE_AXES){
        pselect_.x = (event->mouse.x - BOARD_X) / 95;
        pselect_.y = (event->mouse.y - BOARD_Y) / 95;
    }
    if(event->keyboard.keycode == ALLEGRO_KEY_ENTER || event->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN)
        if(pselect_.selected){//Move pieces
            if(shadow.board[pselect_.y][pselect_.x] == 1){
                pselect_.selected = false;
                move_piece(pselect_.select_x, pselect_.select_y, pselect_.x, pselect_.y);
                shadow_mark(pselect_.x, pselect_.y);
                if(is_checkmate()){
                    checkmate_bubble.playing = true;
                    play_checkmate(crt_turn % 2 == 0 ? false : true);
                }
                pselect_.select_x = -1;
                pselect_.select_y = -1;
                play_lay_piece();
                //Move;
                
            }
            else{
                pselect_.selected = false;
                pselect_.select_x = -1;
                pselect_.select_y = -1;
                //Cancel;
        }
        
    }
    else if(pselect_.selected == false && crt_board[pselect_.y][pselect_.x] != 0
    && crt_turn % 2 == (crt_board[pselect_.y][pselect_.x] > 0 ? 1 : 0))
    {
        pselect_.selected = true;
        pselect_.select_x = pselect_.x;
        pselect_.select_y = pselect_.y;
        play_uplift_piece();
    }

    if(pselect_.x < 0){
        pselect_.x = 0;
        pselect_.selected = false;
    }// To ensure the selected is flase at the beginning
    if(event->keyboard.keycode == ALLEGRO_KEY_LEFT)
        pselect_.x -= 1;
    if(event->keyboard.keycode == ALLEGRO_KEY_RIGHT)
        pselect_.x += 1;
    if(event->keyboard.keycode == ALLEGRO_KEY_UP)
        pselect_.y -= 1;
    if(event->keyboard.keycode == ALLEGRO_KEY_DOWN)
        pselect_.y += 1;

    if(pselect_.x < 0)
        pselect_.x = BOARD_COL-1;
    if(pselect_.y < 0)
        pselect_.y = BOARD_ROW-1;

    if(pselect_.x >= BOARD_COL)
        pselect_.x = 0;
    if(pselect_.y >= BOARD_ROW)
        pselect_.y = 0;
}

void pselect_draw(){
    if (pselect_.x < 0 || pselect_.y < 0) return;
    al_draw_bitmap(pselect_.piece_select[pselect_.selected ? 1 : 0], pselect_.x * 95 + BOARD_X,
    pselect_.y * 95 + BOARD_Y, 0);
}

void shadow_init(){
    shadow._sheet = al_load_bitmap("res/dot.png");
    memset(shadow.board, 0, sizeof(shadow.board));
    if(!shadow._sheet){
        printf("Error loading shadow.png\n");
        exit(1);
    }
}
void shadow_clean(){
    al_destroy_bitmap(shadow._sheet);
}
void shadow_update(){
    if(pselect_.selected && pselect_.x == pselect_.select_x && pselect_.y == pselect_.select_y)
        shadow_mark(pselect_.x, pselect_.y);
    else if(pselect_.selected == false)
        memset(shadow.board, 0, sizeof(shadow.board));
}

bool is_checkmate(){
    for(int i = 0; i < BOARD_ROW; i++){
        for(int j = 0; j < BOARD_COL; j++){
            if(shadow.board[i][j] == 1){
                if(crt_board[i][j] == (crt_turn % 2 == 0 ? R_GENERAL : B_GENERAL)){
                    return true;
                }
            }
        }
    }

}

bool is_ally(int self, int piece){
    if(self == 0 || piece == 0) return false;
    if(self > 0 && self <= B_PAWN && piece > 0 && piece <= B_PAWN) return true;
    if(self <= R_GENERAL && piece <= R_GENERAL ) return true;
    return false;
}

bool is_enemy(int self, int piece){
    if(self == 0 || piece == 0) return false;
    if(self > 0 && self <= B_PAWN && piece <= R_GENERAL ) return true;
    if(self <= R_GENERAL && piece > 0 && piece <= B_PAWN) return true;
    return false;
}

bool movable(int self, int piece){
    if(is_ally(self, piece)) return false;
    if(is_enemy(self, piece) || piece == 0) return true;
    return false;
}

void shadow_mark(int x, int y){
    int self = crt_board[y][x];
    switch (crt_board[y][x])
    {
    case B_GENERAL:
        if(x-1 >= 3 && movable(self,crt_board[y][x-1]))
            shadow.board[y][x-1] = 1;
        if(x+1 <= 5 && movable(self,crt_board[y][x+1])) 
            shadow.board[y][x+1] = 1;
        if(y-1 >= 0 && movable(self,crt_board[y-1][x]))
            shadow.board[y-1][x] = 1;
        if(y+1 <= 2 && movable(self,crt_board[y+1][x]))
            shadow.board[y+1][x] = 1;
        break;
    case R_GENERAL:
        if(x-1 >= 3 && movable(self,crt_board[y][x-1]))
            shadow.board[y][x-1] = 1;
        if(x+1 <= 5 && movable(self,crt_board[y][x+1])) 
            shadow.board[y][x+1] = 1;
        if(y-1 >= 7 && movable(self,crt_board[y-1][x]))
            shadow.board[y-1][x] = 1;
        if(y+1 <= 9 && movable(self,crt_board[y+1][x]))
            shadow.board[y+1][x] = 1;
        break;
    case B_GUARD:
        if(x-1 >= 3 && y-1 >= 0 && movable(self,crt_board[y-1][x-1]))
            shadow.board[y-1][x-1] = 1;
        if(x+1 <= 5 && y-1 >= 0 && movable(self,crt_board[y-1][x+1]))
            shadow.board[y-1][x+1] = 1;
        if(x-1 >= 3 && y+1 <= 2 && movable(self,crt_board[y+1][x-1]))
            shadow.board[y+1][x-1] = 1;
        if(x+1 <= 5 && y+1 <= 2 && movable(self,crt_board[y+1][x+1]))
            shadow.board[y+1][x+1] = 1;
        break;
    case R_GUARD:
        if(x-1 >= 3 && y-1 >= 7 && movable(self,crt_board[y-1][x-1]))
            shadow.board[y-1][x-1] = 1;
        if(x+1 <= 5 && y-1 >= 7 && movable(self,crt_board[y-1][x+1]))
            shadow.board[y-1][x+1] = 1;
        if(x-1 >= 3 && y+1 <= 9 && movable(self,crt_board[y+1][x-1]))
            shadow.board[y+1][x-1] = 1;
        if(x+1 <= 5 && y+1 <= 9 && movable(self,crt_board[y+1][x+1]))
            shadow.board[y+1][x+1] = 1;
        break;
    case R_KNIGHT:
    case B_KNIGHT:
        if(x-1 >= 0 && y-2 >= 0 && crt_board[y-1][x] == 0 && movable(self,crt_board[y-2][x-1]))
            shadow.board[y-2][x-1] = 1;
        if(x+1 <= 8 && y-2 >= 0 && crt_board[y-1][x] == 0 && movable(self,crt_board[y-2][x+1]))
            shadow.board[y-2][x+1] = 1;
        if(x-2 >= 0 && y-1 >= 0 && crt_board[y][x-1] == 0 && movable(self,crt_board[y-1][x-2]))
            shadow.board[y-1][x-2] = 1;
        if(x+2 <= 8 && y-1 >= 0 && crt_board[y][x+1] == 0 && movable(self,crt_board[y-1][x+2]))
            shadow.board[y-1][x+2] = 1;
        if(x-1 >= 0 && y+2 <= 9 && crt_board[y+1][x] == 0 && movable(self,crt_board[y+2][x-1]))
            shadow.board[y+2][x-1] = 1;
        if(x+1 <= 8 && y+2 <= 9 && crt_board[y+1][x] == 0 && movable(self,crt_board[y+2][x+1]))
            shadow.board[y+2][x+1] = 1;
        if(x-2 >= 0 && y+1 <= 9 && crt_board[y][x-1] == 0 && movable(self,crt_board[y+1][x-2]))
            shadow.board[y+1][x-2] = 1;
        if(x+2 <= 8 && y+1 <= 9 && crt_board[y][x+1] == 0 && movable(self,crt_board[y+1][x+2]))
            shadow.board[y+1][x+2] = 1;
        break;
    case R_MINISTER:
    case B_MINISTER:
        if(x-2 >= 0 && y-2 >= 0 && crt_board[y-1][x-1] == 0 && movable(self,crt_board[y-2][x-2]))
            shadow.board[y-2][x-2] = 1;
        if(x+2 <= 8 && y-2 >= 0 && crt_board[y-1][x+1] == 0 && movable(self,crt_board[y-2][x+2]))
            shadow.board[y-2][x+2] = 1;
        if(x-2 >= 0 && y+2 <= 9 && crt_board[y+1][x-1] == 0 && movable(self,crt_board[y+2][x-2]))
            shadow.board[y+2][x-2] = 1;
        if(x+2 <= 8 && y+2 <= 9 && crt_board[y+1][x+1] == 0 && movable(self,crt_board[y+2][x+2]))
            shadow.board[y+2][x+2] = 1;
        break;
    case R_ROOKS:
    case B_ROOKS:
        for(int i = x-1; i >= 0; i--){
            if(crt_board[y][i] == 0)
                shadow.board[y][i] = 1;
            else{
                if(is_enemy(self, crt_board[y][i])){
                    shadow.board[y][i] = 1;
                }
                break;
            }
        }
        for(int i = x+1; i <= 8; i++){
            if(crt_board[y][i] == 0)
                shadow.board[y][i] = 1;
            else{
                if(is_enemy(self, crt_board[y][i])){
                    shadow.board[y][i] = 1;
                }
                break;
            }
        }
        for(int i = y-1; i >= 0; i--){
            if(crt_board[i][x] == 0)
                shadow.board[i][x] = 1;
            else{
                if(is_enemy(self, crt_board[i][x])){
                    shadow.board[i][x] = 1;
                }
                break;
            }
        }
        for(int i = y+1; i <= 9; i++){
            if(crt_board[i][x] == 0)
                shadow.board[i][x] = 1;
            else{
                if(is_enemy(self, crt_board[i][x])){
                    shadow.board[i][x] = 1;
                }
                break;
            }
        }
        break;
    case R_CANNON:
    case B_CANNON:
        for(int i = x-1; i >= 0; i--){
            if(crt_board[y][i] == 0)
                shadow.board[y][i] = 1;
            else{
                for(int j = i-1; j >= 0; j--){
                    if(crt_board[y][j] != 0){
                        if(is_enemy(self, crt_board[y][j])) shadow.board[y][j] = 1;
                        break;
                    }
                }
                break;
            }
        }
        for(int i = x+1; i <= 8; i++){
            if(crt_board[y][i] == 0)
                shadow.board[y][i] = 1;
            else{
                for(int j = i+1; j <= 8; j++){
                    if(crt_board[y][j] != 0){
                        if(is_enemy(self, crt_board[y][j])) shadow.board[y][j] = 1;
                        break;
                    }
                }
                break;
            }
        }
        for(int i = y-1; i >= 0; i--){
            if(crt_board[i][x] == 0)
                shadow.board[i][x] = 1;
            else{
                for(int j = i-1; j >= 0; j--){
                    if(crt_board[j][x] != 0){
                        if(is_enemy(self, crt_board[j][x])) shadow.board[j][x] = 1;
                        break;
                    }
                }
                break;
            }
        }
        for(int i = y+1; i <= 9; i++){
            if(crt_board[i][x] == 0)
                shadow.board[i][x] = 1;
            else{
                for(int j = i+1; j <= 9; j++){
                    if(crt_board[j][x] != 0){
                        if(is_enemy(self, crt_board[j][x])) shadow.board[j][x] = 1;
                        break;
                    }
                }
                break;
            }
        }
        break;
    case R_PAWN:
        if(y-1 >= 0 && movable(self,crt_board[y-1][x]))
            shadow.board[y-1][x] = 1;
        if(y <= 4){
            if(x-1 >= 0 && movable(self,crt_board[y][x-1]))
                shadow.board[y][x-1] = 1;
            if(x+1 <= 8 && movable(self,crt_board[y][x+1]))
                shadow.board[y][x+1] = 1;
        }
        break;
    case B_PAWN:
        if(y+1 <= 9 && movable(self,crt_board[y+1][x]))
            shadow.board[y+1][x] = 1;
        if(y >= 5){
            if(x-1 >= 0 && movable(self,crt_board[y][x-1]))
                shadow.board[y][x-1] = 1;
            if(x+1 <= 8 && movable(self,crt_board[y][x+1]))
                shadow.board[y][x+1] = 1;
        }
        break;
    default:
        break;
    }
}
void shadow_draw(){
    if (pselect_.selected == false) return;
    for(int i = 0; i < BOARD_ROW; i++){
        for(int j = 0; j < BOARD_COL; j++){
            if(shadow.board[i][j] == 1){
                al_draw_bitmap(shadow._sheet, j*95 + BOARD_X, i*95 + BOARD_Y, 0);
            }
        }
    }
}


void move_piece(int x, int y, int x1, int y1){
    if(crt_board[y1][x1] != 0) eat_piece(x1, y1);
    crt_board[y1][x1] = crt_board[y][x];
    crt_board[y][x] = 0;
    crt_turn++;
}

void eat_piece(int x1, int y1){
    play_eat(crt_turn % 2 == 0 ? true : false);
    eat_bubble.playing = true;
    
    if(crt_board[y1][x1] == B_GENERAL){
        win_texts.win = 1;
        win_texts.win_side = true;
        game->state = GAME_END;
    }
    if(crt_board[y1][x1] == R_GENERAL){
        win_texts.win = 1;
        win_texts.win_side = false;
        game->state = GAME_END;
    }
    
}